home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_300 / 333_01 / awk3.c < prev    next >
C/C++ Source or Header  |  1989-04-21  |  32KB  |  1,469 lines

  1. /* awk3.c -- Builtin functions and various utility procedures
  2.    Copyright (C) 1986,1987 Free  Software Foundation
  3.    Written by Jay Fenlason, December 1986
  4.  */
  5.  
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <math.h>
  10. #include <time.h>
  11. #include <errno.h>
  12. #include "awk.h"
  13.  
  14.  
  15.  
  16. struct redirect
  17. {
  18.     int         flag;      /* type of redirection */
  19.     NODE           *value;
  20.     FILE           *fp;
  21. };
  22. typedef struct redirect     REDIRECT;
  23.  
  24. static REDIRECT reds[20];    /* An arbitrary limit, surely, but there's an
  25.                  * arbitrary limit on open files, too.  So it
  26.                  * doesn't make much difference, does it? */
  27.  
  28.  
  29. long            NR;
  30. int             NF;
  31.  
  32. /* Set all the special variables to their initial values.  Also sets up
  33.    the dumb[] array for force_string */
  34.  
  35. VOID PASCAL init_vars(void)
  36. {
  37.     register int      i;
  38.     auto     NODE    **tmp;
  39.  
  40.     FS_node      = spc_var("FS", make_string("[\t ]+", 5));
  41.     NF_node      = spc_var("NF", make_number(0.0));
  42.     RS_node      = spc_var("RS", make_string("\n", 1));
  43.     NR_node      = spc_var("NR", make_number(0.0));
  44.     FILENAME_node = spc_var("FILENAME", Nnull_string);
  45.     OFS_node      = spc_var("OFS", make_string(" ", 1));
  46.     ORS_node      = spc_var("ORS", make_string("\n", 1));
  47.     OFMT_node      = spc_var("OFMT", make_string("%.6g", 4));
  48.     FNR_node      = spc_var("FNR", make_number(0.0));
  49.     RLENGTH_node  = spc_var("RLENGTH", make_number(0.0));
  50.     RSTART_node   = spc_var("RSTART", make_number(0.0));
  51.     SUBSEP_node   = spc_var("SUBSEP", make_string("\034", 1));
  52.     ARGC_node      = spc_var("ARGC", make_number(1.0));
  53.     ARGV_node      = variable("ARGV");
  54.     assoc_clear(ARGV_node);
  55.     tmp  = assoc_lookup(ARGV_node, tmp_number((AWKNUM) 0.0), ASSOC_CREATE);
  56.     *tmp = make_string(myname, strlen(myname));
  57.  
  58.     /* This ugly hack is used by force_string to fake a call to sprintf */
  59.     dumb[0].type  = NODE_EXPRESSION_LIST;
  60.     dumb[0].lnode = OFMT_node;
  61.     dumb[0].rnode = &dumb[1];
  62.     dumb[1].type  = NODE_EXPRESSION_LIST;
  63.     dumb[1].lnode = (NODE *) NULL; /* fill in the var here */
  64.     dumb[1].rnode = (NODE *) NULL;
  65.  
  66.     for (i = 0; i < MAXDIM(reds); ++i)
  67.     reds[i].flag = NODE_ILLEGAL;
  68.  
  69.     return;
  70. }
  71.  
  72.  
  73. /* OFMT is special because we don't dare use force_string on it for fear of
  74.    infinite loops.  Thus, if it isn't a string, we return the default "%.6g"
  75.    This may or may not be the right thing to do, but its the easiest */
  76. /* This routine isn't used!  It should be.  */
  77.  
  78. char * PASCAL get_ofmt(void)
  79. {
  80.     register NODE      *tmp;
  81.  
  82.     tmp = *get_lhs(OFMT_node);
  83.     if (tmp->type != NODE_STRING || tmp->stlen == 0)
  84.     return("%.6g");
  85.     return(tmp->stptr);
  86. }
  87.  
  88.  
  89. REPAT_BUFFER * PASCAL get_fs(void)
  90. {
  91.     register NODE        *tmp;
  92.     auto     char        *err;
  93.     auto     char        *str;
  94.     auto     int         len;
  95.     static   REPAT_BUFFER    fs_repat;
  96.     static   char         fs_fastmap[FASTMAP_SIZE];
  97.     static   char         fs_str[256] = "";
  98.  
  99.     tmp = force_string(FS_node->var_value);
  100.     if (0 == tmp->stlen)
  101.     {
  102.     str = "[\t ]+";
  103.     len = strlen(str);
  104.     }
  105.     else
  106.     {
  107.     str = tmp->stptr;
  108.     len = tmp->stlen;
  109.     }
  110.  
  111.     if (strcmp(str, fs_str))
  112.     {
  113.     strcpy(fs_str, str);
  114.     fs_repat.fastmap      = fs_fastmap;
  115.     fs_repat.used          = 0;
  116.     fs_repat.fastmap_accurate = FALSE;
  117.     fs_repat.can_be_null      = 0;
  118.     if (0 == fs_repat.allocated)
  119.     {
  120.         fs_repat.allocated = 100;
  121.         if (NULL == (fs_repat.buffer = malloc(100)))
  122.         panic("Out of memory for fs_repat buffer");
  123.     }
  124.     err = re_compile_pattern(str, len, &fs_repat);
  125.     if (err)
  126.         panic("Invalid REGEXP(%s) in FS variable: %s", str, err);
  127.     }
  128.  
  129.     return(&fs_repat);
  130. }
  131.  
  132.  
  133. VOID PASCAL set_fs(char *str)
  134. {
  135.     register NODE     **tmp;
  136.  
  137.     tmp = get_lhs(FS_node);
  138.     do_deref();
  139.  
  140.     *tmp = make_string(str, -1);
  141.     return;
  142. }
  143.  
  144.  
  145. VOID PASCAL set_rs(char *str)
  146. {
  147.     register NODE      **tmp;
  148.  
  149.     tmp = get_lhs(RS_node);
  150.     do_deref();
  151.  
  152.     if (*str == 't')
  153.     *str = '\t';
  154.  
  155.     *tmp = make_string(str, 1);
  156.     return;
  157. }
  158.  
  159.  
  160. int PASCAL get_rs(void)
  161. {
  162.     register NODE  *tmp;
  163.  
  164.     tmp = force_string(RS_node->var_value);
  165.     if (tmp->stlen == 0)
  166.     return('\n');
  167.     return(*(tmp->stptr));
  168. }
  169.  
  170.  
  171. /* Builtin functions */
  172.  
  173.  
  174. NODE * PASCAL do_match(NODE *tree)
  175. {
  176.     auto     int          idx;
  177.     auto     NODE         *str, *reg_node;
  178.     auto     char         *err;
  179.     auto     REPAT_BUFFER    *rp;
  180.     auto     REREGS          regs;
  181.  
  182.     get_two(tree, &str, ®_node);
  183.     str = force_string(str);
  184.     if (NODE_REGEXP == reg_node->type)
  185.     rp = reg_node->rereg;
  186.     else
  187.     {
  188.     reg_node = force_string(reg_node);
  189.     clear_wrk_repat();
  190.     rp  = &wrk_repat;
  191.     err = re_compile_pattern(reg_node->stptr, reg_node->stlen, rp);
  192.     if (err)
  193.         panic("Invalid REGEXP(%s) in match(): %s", reg_node->stptr, err);
  194.     }
  195.     idx = re_search(rp, str->stptr, str->stlen, 0, str->stlen, ®s);
  196.     if (idx < 0)
  197.     {
  198.     assign_number(&RSTART_node->var_value,    (AWKNUM) 0.0);
  199.     assign_number(&RLENGTH_node->var_value, (AWKNUM) 0.0);
  200.     idx = 0;
  201.     }
  202.     else
  203.     {
  204.     assign_number(&RSTART_node->var_value,    (AWKNUM) ++idx);
  205.     assign_number(&RLENGTH_node->var_value,
  206.               (AWKNUM) (regs.end[0] - regs.start[0]));
  207.     }
  208.     return(tmp_number((AWKNUM) idx));
  209. }
  210.  
  211.  
  212. NODE * PASCAL do_sub(NODE *tree)
  213. {
  214.     auto     int          idx, len;
  215.     auto     int          match_len;
  216.     auto     NODE         *regexp, *str1, *str2;
  217.     auto     char         *wrk, *pwrk;
  218.     auto     REPAT_BUFFER    *rp;
  219.     auto     REREGS          regs;
  220.  
  221.     get_three(tree, ®exp, &str1, &str2);
  222.     str1 = force_string(str1);
  223.     str2 = force_string(str2);
  224.     if (NODE_REGEXP == regexp->type)
  225.     rp = regexp->rereg;
  226.     else
  227.     {
  228.     regexp = force_string(regexp);
  229.     clear_wrk_repat();
  230.     rp  = &wrk_repat;
  231.     wrk = re_compile_pattern(regexp->stptr, regexp->stlen, rp);
  232.     if (wrk)
  233.         panic("Invalid REGEXP(%s) in sub(): %s", regexp->stptr, wrk);
  234.     }
  235.  
  236.     idx  = re_search(rp, str2->stptr, str2->stlen, 0, str2->stlen, ®s);
  237.     if (idx < 0)
  238.     return(tmp_number((AWKNUM) 0.0));
  239.  
  240.     match_len = regs.end[0] - regs.start[0];
  241.     wrk = malloc(str2->stlen - match_len + str1->stlen + 1);
  242.     if (NULL == wrk)
  243.     panic("Out of memory in do_sub()");
  244.  
  245.     pwrk = wrk;
  246.     if (idx > 0)
  247.     {
  248.     memcpy(pwrk, str2->stptr, idx);
  249.     pwrk += idx;
  250.     }
  251.     memcpy(pwrk, str1->stptr, str1->stlen);
  252.     pwrk += str1->stlen;
  253.     len = idx + match_len;
  254.     if (len < str2->stlen)
  255.     {
  256.     memcpy(pwrk, str2->stptr + len, str2->stlen - len);
  257.     pwrk += str2->stlen - len;
  258.     }
  259.     *pwrk = EOS;
  260.  
  261.     len  = str2->stlen - match_len + str1->stlen;
  262.     str1 = tree->rnode->rnode->lnode;
  263.     *get_lhs(str1) = dupnode(tmp_string(wrk, len));
  264.     do_deref();
  265.     free(wrk);
  266.  
  267.     /* If the modified string is a field variable we need to update the   */
  268.     /* value of the field variables.  If $0 was changed we need to recalc */
  269.     /* all the fields.    If an individual field was modified we need to      */
  270.     /* recalc $0. - BW 12/21/88                       */
  271.     if (NODE_FIELD_SPEC == str1->type)
  272.     field_spec_changed(str1->lnode->numbr);
  273.  
  274.     return(tmp_number((AWKNUM) 1.0));
  275. }
  276.  
  277.  
  278. NODE * PASCAL do_gsub(NODE *tree)
  279. {
  280.     auto     int           idx, len, strlen;
  281.     auto     int           match_len;
  282.     auto     int           hits = 0;
  283.     auto     int           ofs  = 0;
  284.     auto     NODE          *regexp, *str1, *str2;
  285.     auto     char          *cur2, *new2, *p;
  286.     auto     REPAT_BUFFER     *rp;
  287.     auto     REREGS           regs;
  288.  
  289.     get_three(tree, ®exp, &str1, &str2);
  290.     str1 = force_string(str1);
  291.     str2 = force_string(str2);
  292.     if (NODE_REGEXP == regexp->type)
  293.     rp = regexp->rereg;
  294.     else
  295.     {
  296.     regexp = force_string(regexp);
  297.     clear_wrk_repat();
  298.     rp = &wrk_repat;
  299.     p = re_compile_pattern(regexp->stptr, regexp->stlen, rp);
  300.     if (p)
  301.         panic("Invalid REGEXP(%s) in gsub(): %s", regexp->stptr, p);
  302.     }
  303.  
  304.     idx  = re_search(rp, str2->stptr, str2->stlen, 0, str2->stlen, ®s);
  305.     if (idx < 0)
  306.     return(tmp_number((AWKNUM) 0.0));
  307.  
  308.     match_len = regs.end[0] - regs.start[0];
  309.     strlen    = str2->stlen;